//+------------------------------------------------------------------+
//|                                                  SignalStoch.mqh |
//|                             Copyright 2000-2025, MetaQuotes Ltd. |
//|                                             https://www.mql5.com |
//+------------------------------------------------------------------+
#include <Expert/ExpertSignal.h>    // 专家顾问信号基类（提供信号生成框架）

// wizard description start（MQL5 策略向导描述，用于识别类信息与参数）
//+------------------------------------------------------------------+
//| 类功能描述                                                       |
//| Title=基于随机振荡器（Stochastic Oscillator）的交易信号            |
//| Type=SignalAdvanced                                              |
//| Name=Stochastic                                                  |
//| ShortName=Stoch                                                  |
//| Class=CSignalStoch                                               |
//| Page=signal_stochastic                                           |
//| Parameter=PeriodK,int,8,%K周期（随机振荡器快速线计算周期）            |
//| Parameter=PeriodD,int,3,%D周期（随机振荡器信号线平滑周期）            |
//| Parameter=PeriodSlow,int,3,慢速周期（随机振荡器%K线平滑周期）         |
//| Parameter=Applied,ENUM_STO_PRICE,STO_LOWHIGH,应用价格（计算随机振荡器的基础价格类型）|
//+------------------------------------------------------------------+
// wizard description end

//+------------------------------------------------------------------+
//| CSignalStoch 类：基于随机振荡器（Stochastic）的交易信号生成器        |
//| 核心能力：继承自 CExpertSignal，通过调用随机振荡器（反映价格在近期波动区间内位置的震荡指标）， |
//|           识别5类多空信号（趋势方向、趋势反转、线交叉、普通背离、双重背离），   |
//|           支持通过“信号权重”调整不同形态的优先级，适配震荡行情与趋势反转场景       |
//| 核心逻辑：随机振荡器计算公式=%K=[(收盘价-近期低点)/(近期高点-近期低点)]×100，%D=%K的EMA； |
//|           通过“%K线趋势”“%K与%D线交叉”“指标与价格背离”判断信号，默认超买=80、超卖=20 |
//| 适用场景：中短线震荡交易（擅长捕捉区间高低点）与趋势末端反转（通过背离），适合股票、期货、外汇等 |
//|           品种，需与趋势指标（如均线）配合过滤趋势中的假信号             |
//+------------------------------------------------------------------+
class CSignalStoch : public CExpertSignal
  {
protected:
   // 核心组件与参数（保护，子类可访问）
   CiStochastic      m_stoch;          // 随机振荡器对象（封装%K线、%D线计算与数据读取）
   CPriceSeries     *m_app_price_high; // 高价序列指针（用于判断向下背离的价格高点数据）
   CPriceSeries     *m_app_price_low;  // 低价序列指针（用于判断向上背离的价格低点数据）
   // 随机振荡器可调参数（与指标原生参数对应，默认配置平衡灵敏度与稳定性）
   int               m_periodK;        // %K周期（快速线计算周期，默认8，值越小反应越快）
   int               m_periodD;        // %D周期（信号线平滑周期，默认3，对%K线进行EMA平滑）
   int               m_period_slow;    // 慢速周期（%K线平滑周期，默认3，降低%K线波动频率）
   ENUM_STO_PRICE    m_applied;        // 应用价格类型（默认STO_LOWHIGH，基于高低价计算波动区间）
   // 市场形态信号权重（0-100，值越大信号优先级越高，默认配置突出背离信号）
   int               m_pattern_0;      // 形态0权重：%K线趋势符合预期方向（如多单需%K线向上）
   int               m_pattern_1;      // 形态1权重：%K线趋势反转（如%K线从向下转为向上）
   int               m_pattern_2;      // 形态2权重：%K线与%D线交叉（如%K从下上穿%D→多单）
   int               m_pattern_3;      // 形态3权重：普通背离（价格与%K线极值反向变化，如价格新低、指标不新低）
   int               m_pattern_4;      // 形态4权重：双重背离（连续两次普通背离，反转信号更强）
   // 极值分析辅助变量（用于背离信号判断，存储指标与价格的极值关系）
   double            m_extr_osc[10];   // 随机振荡器极值数组（存储最近10个%K线极值点）
   double            m_extr_pr[10];    // 对应价格极值数组（存储%K线极值点对应的价格极值）
   int               m_extr_pos[10];   // 极值位置数组（存储极值点对应的K线偏移量，单位：根）
   uint              m_extr_map;       // 极值关系位图（用二进制位记录指标与价格极值的相对关系，辅助背离判断）

public:
   //----------------------------------------------------------------
   // 构造与析构函数
   //----------------------------------------------------------------
   /**
    * @brief 构造函数：初始化随机振荡器信号生成器
    * @details 1. 初始化随机振荡器对象及默认参数（%K=8、%D=3、慢速=3，应用价格=STO_LOWHIGH）；
    *          2. 设置默认信号权重（形态0=30，形态1=60，形态2=50，形态3=100，形态4=90）；
    *          3. 启用全价格序列（开盘+最高+最低+收盘），因背离与交叉分析需多维度价格数据；
    *          4. 初始化价格序列指针为NULL，后续在InitIndicators中绑定具体序列；
    *          5. 继承父类 CExpertSignal 的信号框架初始化
    */
                     CSignalStoch(void);

   /**
    * @brief 析构函数：清理随机振荡器信号生成器资源
    * @details 释放振荡器对象及价格序列指针占用的内存，依赖父类析构逻辑完成信号框架资源清理
    */
                    ~CSignalStoch(void);

   //----------------------------------------------------------------
   // 随机振荡器参数配置：修改核心指标参数（外部调用接口）
   //----------------------------------------------------------------
   /**
    * @brief 设置%K周期（快速线计算周期，核心参数）
    * @param value [in] 周期值（需>0，建议5-14，值越小%K线波动越频繁，灵敏度越高）
    */
   void              PeriodK(int value);

   /**
    * @brief 设置%D周期（信号线平滑周期，核心参数）
    * @param value [in] 周期值（需>0，建议2-5，值越大%D线越平滑，信号滞后性略增）
    */
   void              PeriodD(int value);

   /**
    * @brief 设置慢速周期（%K线平滑周期，核心参数）
    * @param value [in] 周期值（需>0，建议2-5，值越大%K线波动越平缓，过滤噪音效果越好）
    */
   void              PeriodSlow(int value);

   /**
    * @brief 设置应用价格类型（计算波动区间的基础价格）
    * @param value [in] 价格类型（ENUM_STO_PRICE 枚举，如 STO_LOWHIGH=基于高低价、STO_CLOSECLOSE=基于收盘价）
    */
   void              Applied(ENUM_STO_PRICE value);

   //----------------------------------------------------------------
   // 信号权重配置：修改不同市场形态的信号强度（外部调用接口）
   //----------------------------------------------------------------
   /**
    * @brief 设置形态0（%K线趋势方向）的信号权重
    * @param value [in] 权重值（0-100，建议20-40，值越大越重视趋势延续的弱确认信号）
    */
   void              Pattern_0(int value);

   /**
    * @brief 设置形态1（%K线趋势反转）的信号权重
    * @param value [in] 权重值（0-100，建议50-70，值越大越重视趋势转向的中期信号）
    */
   void              Pattern_1(int value);

   /**
    * @brief 设置形态2（%K与%D线交叉）的信号权重
    * @param value [in] 权重值（0-100，建议40-60，值越大越重视动量变化的交叉信号）
    */
   void              Pattern_2(int value);

   /**
    * @brief 设置形态3（普通背离）的信号权重
    * @param value [in] 权重值（0-100，建议90-100，值越大越重视趋势反转的强信号）
    */
   void              Pattern_3(int value);

   /**
    * @brief 设置形态4（双重背离）的信号权重
    * @param value [in] 权重值（0-100，建议80-90，值越大越重视连续背离的确认信号）
    */
   void              Pattern_4(int value);

   //----------------------------------------------------------------
   // 参数验证：确保指标参数与信号配置有效（信号生成前提）
   //----------------------------------------------------------------
   /**
    * @brief 验证随机振荡器参数与信号配置的有效性
    * @return bool - 验证结果：true=所有参数有效，false=存在无效参数（如%K或%D周期≤0）
    * @note 验证逻辑：
    *       1. 先调用父类 ValidationSettings() 验证信号框架基础参数（如品种、周期）；
    *       2. 核心验证：%K周期（m_periodK）和%D周期（m_periodD）必须>0，否则输出错误日志并返回false；
    *       3. 慢速周期（m_period_slow）和应用价格（m_applied）由枚举/整数类型限制，无需额外验证
    */
   virtual bool      ValidationSettings(void);

   //----------------------------------------------------------------
   // 指标初始化：创建并注册随机振荡器（信号生成的前提）
   //----------------------------------------------------------------
   /**
    * @brief 初始化随机振荡器及信号所需的价格序列数据
    * @param indicators [in] 指标集合对象（用于管理所有策略用到的指标，如随机振荡器、均线等）
    * @return bool - 初始化结果：true=成功（指标创建+价格序列绑定+注册到指标集合），false=失败
    * @note 调用流程：
    *       1. 先调用父类 InitIndicators() 完成基础信号框架与价格序列初始化；
    *       2. 调用内部 InitStoch() 方法创建随机振荡器，绑定当前品种、周期及所有指标参数；
    *       3. 根据应用价格类型（m_applied）绑定价格序列指针（如STO_LOWHIGH绑定高低价序列，STO_CLOSECLOSE绑定收盘价序列）；
    *       4. 若指标创建或序列绑定失败，返回 false 并终止信号生成
    */
   virtual bool      InitIndicators(CIndicators *indicators);

   //----------------------------------------------------------------
   // 信号判断核心方法：生成多空信号权重（策略决策依据）
   //----------------------------------------------------------------
   /**
    * @brief 判断当前市场是否满足多单（买入）开仓条件，返回信号权重
    * @return int - 多单信号权重（0-100，0=无信号，值越大信号越强烈）
    * @note 核心判断逻辑（基于随机振荡器特性，%K线向上为前提）：
    *       1. 形态0（趋势方向）：%K线向上 → 返回形态0权重（弱确认信号）；
    *       2. 形态1（趋势反转）：%K线从向下转为向上 → 返回形态1权重（中期转向）；
    *       3. 形态2（线交叉）：%K线从下上穿%D线（金叉） → 返回形态2权重（动量变化信号）；
    *       4. 形态3（普通背离）：调用 ExtStateStoch() 生成极值数据，通过 CompareMaps() 验证价格新低但%K线不新低 → 返回形态3权重；
    *       5. 形态4（双重背离）：验证连续两次普通背离 → 直接返回形态4权重（优先级最高）；
    *       6. 信号优先级：形态3 > 形态4 > 形态1 > 形态2 > 形态0
    */
   virtual int       LongCondition(void);

   /**
    * @brief 判断当前市场是否满足空单（卖出）开仓条件，返回信号权重
    * @return int - 空单信号权重（0-100，0=无信号，值越大信号越强烈）
    * @note 核心判断逻辑（基于随机振荡器特性，%K线向下为前提）：
    *       1. 形态0（趋势方向）：%K线向下 → 返回形态0权重（弱确认信号）；
    *       2. 形态1（趋势反转）：%K线从向上转为向下 → 返回形态1权重（中期转向）；
    *       3. 形态2（线交叉）：%K线从上下穿%D线（死叉） → 返回形态2权重（动量变化信号）；
    *       4. 形态3（普通背离）：调用 ExtStateStoch() 生成极值数据，通过 CompareMaps() 验证价格新高但%K线不新高 → 返回形态3权重；
    *       5. 形态4（双重背离）：验证连续两次普通背离 → 直接返回形态4权重（优先级最高）；
    *       6. 信号优先级：形态3 > 形态4 > 形态1 > 形态2 > 形态0
    */
   virtual int       ShortCondition(void);

protected:
   //----------------------------------------------------------------
   // 内部辅助方法：随机振荡器初始化（仅内部调用）
   //----------------------------------------------------------------
   /**
    * @brief 创建并初始化随机振荡器（绑定品种、周期、参数，注册到指标集合）
    * @param indicators [in] 指标集合对象（用于管理随机振荡器）
    * @return bool - 初始化结果：true=成功（指标创建+参数配置完成），false=失败
    * @note 内部流程：
    *       1. 检查指标集合指针有效性；
    *       2. 将随机振荡器对象（m_stoch）添加到指标集合；
    *       3. 调用 m_stoch.Create() 绑定当前交易品种、周期及所有指标参数（%K/%D/慢速周期、应用价格、平滑方法=SMA）；
    *       4. 若添加或创建失败，输出错误日志并返回 false
    */
   bool              InitStoch(CIndicators *indicators);

   //----------------------------------------------------------------
   // 数据读取与状态分析：快捷获取指标数据及判断状态（保护，子类可直接调用）
   //----------------------------------------------------------------
   /**
    * @brief 获取指定索引的随机振荡器%K线（主信号线）值
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - %K线值（0-100，>80=超买，<20=超卖，反映价格在近期波动区间的位置）
    */
   double            Main(int ind);

   /**
    * @brief 计算指定索引K线的%K线差值（当前K线 - 前一根K线，反映%K线趋势方向）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=%K线向上，<0=%K线向下，反映动量趋势方向）
    */
   double            DiffMain(int ind);

   /**
    * @brief 获取指定索引的随机振荡器%D线（信号线）值
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - %D线值（%K线的EMA平滑线，用于与%K线交叉产生交易信号）
    */
   double            Signal(int ind);

   /**
    * @brief 计算指定索引K线的%D线差值（当前K线 - 前一根K线，反映%D线趋势方向）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=%D线向上，<0=%D线向下，辅助判断动量强度）
    */
   double            DiffSignal(int ind);

   /**
    * @brief 计算指定索引K线的%K线与%D线差值（反映交叉状态）
    * @param ind [in] 索引（0=当前K线，1=前一根K线，以此类推）
    * @return double - 差值（>0=%K线在%D线上方，<0=%K线在%D线下方，用于判断金叉/死叉）
    */
   double            DiffMainSignal(int ind);

   /**
    * @brief 分析指定索引K线的%K线趋势状态（连续同方向变化的K线数量）
    * @param ind [in] 索引（分析起点K线）
    * @return int - 趋势状态值（正数=连续向上变化的K线数，负数=连续向下变化的K线数，0=无连续趋势）
    * @note 例如返回 3 表示从 ind 开始连续3根K线%K线向上，返回 -2 表示连续2根向下，用于识别指标极值点
    */
   int               StateStoch(int ind);

   /**
    * @brief 扩展分析随机振荡器与价格的极值关系（生成背离判断所需的极值位图）
    * @param ind [in] 索引（分析起点K线）
    * @return bool - 分析结果：true=成功（生成极值数组与位图），false=失败（数据不足）
    * @note 核心逻辑：
    *       1. 从 ind 开始遍历K线，通过 StateStoch() 识别%K线的极值点（连续同方向变化的转折点）；
    *       2. 记录每个指标极值点对应的价格极值（指标低点对应价格低点，指标高点对应价格高点）；
    *       3. 用 m_extr_map 位图记录相邻极值点的关系（如价格创新低但指标未创新低 → 标记为底背离）；
    *       4. 结果用于形态3（普通背离）和形态4（双重背离）的判断，是此类核心分析逻辑
    */
   bool              ExtStateStoch(int ind);

   /**
    * @brief 对比极值位图与预设模式（验证是否满足背离条件）
    * @param map [in] 预设模式位图（二进制位表示期望的极值关系，如 0x01 表示价格新高、指标不新高）
    * @param count [in] 需验证的极值对数（1=普通背离，2=双重背离）
    * @param minimax [in] 极值类型标识（false=默认，true=区分高低点极值，暂未启用）
    * @param start [in] 验证起始索引（默认0，从第一个极值对开始验证）
    * @return bool - 对比结果：true=极值位图匹配预设模式（满足背离），false=不匹配（不满足背离）
    * @note 核心作用：将复杂的背离判断转化为“位图模式匹配”，通过二进制位验证指标与价格极值的反向关系
    */
   bool              CompareMaps(int map,int count,bool minimax=false,int start=0);

   /**
    * @brief 背离调试打印（内部辅助方法，用于输出极值分析过程数据，帮助调试背离逻辑）
    * @note 实际策略运行中可注释此方法，调试时启用以查看极值数组、位图等关键数据
    */
   void              DiverDebugPrint();
  };
//+------------------------------------------------------------------+